package net.gazhi.delonix.core.thread;

import java.util.HashMap;
import java.util.Map;

import org.springframework.context.ApplicationContext;

/**
 * 线程上下文，用于缓存线程共享数据<br>
 * <br>
 * 配合过滤器或方法拦截器使用，注意线程每次被执行的前后都要清理上下文，防止线程间的数据污染
 * 
 * @author linzb
 * 
 */
public abstract class ThreadContext {

	/** 防止外部类创建对象 */
	protected ThreadContext() {
	}

	/** 进程变量：以ObjectWrapper.class为key，相应的ObjectWrapper对象为值的Map */
	private static final ThreadLocal<Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>>> contextThreadLocal = new ThreadLocal<Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>>>();

	/**
	 * 把某个对象的Wrapper保存到线程变量
	 * 
	 * @param wrapper
	 */
	@SuppressWarnings("unchecked")
	protected static final void set(ObjectWrapper<?> wrapper) {
		Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>> context = contextThreadLocal.get();
		if (context == null) {
			context = new HashMap<Class<ObjectWrapper<?>>, ObjectWrapper<?>>();
			contextThreadLocal.set(context);
		}
		context.put((Class<ObjectWrapper<?>>) wrapper.getClass(), wrapper);
	}

	/**
	 * 根据wrapper类获取所封装的对象
	 * 
	 * @param wrapperClass
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected static final <T> T get(Class<? extends ObjectWrapper<? extends T>> wrapperClass) {
		Map<Class<ObjectWrapper<?>>, ObjectWrapper<?>> cache = contextThreadLocal.get();
		if (cache == null) {
			return null;
		}
		ObjectWrapper<T> wrapper = (ObjectWrapper<T>) cache.get(wrapperClass);
		return wrapper == null ? null : wrapper.getObj();
	}

	/**
	 * 清除线程的缓存对象
	 */
	public static final void clear() {
		contextThreadLocal.remove();
	}

	/*
	 * =========================================================================
	 */

	/**
	 * 缓存 Spring 应用上下文
	 * 
	 * @param appContext
	 */
	public static void setAppContext(ApplicationContext appContext) {
		set(new AppContextWrapper().wrap(appContext));
	}

	/**
	 * 取得缓存中的 Spring 应用上下文
	 * 
	 * @return
	 */
	public static ApplicationContext getAppContext() {
		return get(AppContextWrapper.class);
	}

	/**
	 * 取得 Spring 上下文中的 Bean 对象
	 * 
	 * @param beanClass
	 * @return
	 */
	public static <T> T getBean(Class<T> beanClass) {
		ApplicationContext ctx = getAppContext();
		return ctx == null ? null : ctx.getBean(beanClass);
	}

	/**
	 * 缓存终端 IP 地址
	 * 
	 * @param clientIp
	 */
	public static void setClientIp(long clientIp) {
		set(new ClientIpWrapper().wrap(clientIp));
	}

	/**
	 * 取得终端 IP 地址
	 * 
	 * @return
	 */
	public static long getClientIp() {
		return get(ClientIpWrapper.class);
	}

	private static class AppContextWrapper extends ObjectWrapper<ApplicationContext> {
	}

	private static class ClientIpWrapper extends ObjectWrapper<Long> {

	}

}